/*
    This source file is part of GeNa project.
    Copyright © GeNa project 2008
    For the latest info, see http://code.google.com/p/genaproject/ or  http://lumpyproject.forums-rpg.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */

#include <GL/glew.h>

#include <image.h>
#include <string>
#include <fstream>

#ifdef WX_PRECOMP
#ifndef WX_PCH_H_INCLUDED
#include "wx_pch.h"
#endif
#endif

#define CHECK_FLAGS(var, flags) ((var & (flags)) == (flags))
#define NCHECK_FLAGS(var, flags) ((var & (flags)) != (flags))

#define MAKEFOURCC(s) (unsigned int)s[0] + ((unsigned int)s[1] << 8) + ((unsigned int)s[2] << 16) + ((unsigned int)s[3] << 24)

const unsigned int FOURCC_DDS = MAKEFOURCC("DDS ");
const unsigned int FOURCC_DXT1 = MAKEFOURCC("DXT1");
const unsigned int FOURCC_DXT2 = MAKEFOURCC("DXT2");
const unsigned int FOURCC_DXT3 = MAKEFOURCC("DXT3");
const unsigned int FOURCC_DXT4 = MAKEFOURCC("DXT4");
const unsigned int FOURCC_DXT5 = MAKEFOURCC("DXT5");
const unsigned int FOURCC_DX10 = MAKEFOURCC("DX10");



enum DXGI_FORMAT
{
    DXGI_FORMAT_UNKNOWN = 0,
    DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
    DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
    DXGI_FORMAT_R32G32B32A32_UINT = 3,
    DXGI_FORMAT_R32G32B32A32_SINT = 4,
    DXGI_FORMAT_R32G32B32_TYPELESS = 5,
    DXGI_FORMAT_R32G32B32_FLOAT = 6,
    DXGI_FORMAT_R32G32B32_UINT = 7,
    DXGI_FORMAT_R32G32B32_SINT = 8,
    DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
    DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
    DXGI_FORMAT_R16G16B16A16_UNORM = 11,
    DXGI_FORMAT_R16G16B16A16_UINT = 12,
    DXGI_FORMAT_R16G16B16A16_SNORM = 13,
    DXGI_FORMAT_R16G16B16A16_SINT = 14,
    DXGI_FORMAT_R32G32_TYPELESS = 15,
    DXGI_FORMAT_R32G32_FLOAT = 16,
    DXGI_FORMAT_R32G32_UINT = 17,
    DXGI_FORMAT_R32G32_SINT = 18,
    DXGI_FORMAT_R32G8X24_TYPELESS = 19,
    DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
    DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
    DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
    DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
    DXGI_FORMAT_R10G10B10A2_UNORM = 24,
    DXGI_FORMAT_R10G10B10A2_UINT = 25,
    DXGI_FORMAT_R11G11B10_FLOAT = 26,
    DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
    DXGI_FORMAT_R8G8B8A8_UNORM = 28,
    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
    DXGI_FORMAT_R8G8B8A8_UINT = 30,
    DXGI_FORMAT_R8G8B8A8_SNORM = 31,
    DXGI_FORMAT_R8G8B8A8_SINT = 32,
    DXGI_FORMAT_R16G16_TYPELESS = 33,
    DXGI_FORMAT_R16G16_FLOAT = 34,
    DXGI_FORMAT_R16G16_UNORM = 35,
    DXGI_FORMAT_R16G16_UINT = 36,
    DXGI_FORMAT_R16G16_SNORM = 37,
    DXGI_FORMAT_R16G16_SINT = 38,
    DXGI_FORMAT_R32_TYPELESS = 39,
    DXGI_FORMAT_D32_FLOAT = 40,
    DXGI_FORMAT_R32_FLOAT = 41,
    DXGI_FORMAT_R32_UINT = 42,
    DXGI_FORMAT_R32_SINT = 43,
    DXGI_FORMAT_R24G8_TYPELESS = 44,
    DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
    DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
    DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
    DXGI_FORMAT_R8G8_TYPELESS = 48,
    DXGI_FORMAT_R8G8_UNORM = 49,
    DXGI_FORMAT_R8G8_UINT = 50,
    DXGI_FORMAT_R8G8_SNORM = 51,
    DXGI_FORMAT_R8G8_SINT = 52,
    DXGI_FORMAT_R16_TYPELESS = 53,
    DXGI_FORMAT_R16_FLOAT = 54,
    DXGI_FORMAT_D16_UNORM = 55,
    DXGI_FORMAT_R16_UNORM = 56,
    DXGI_FORMAT_R16_UINT = 57,
    DXGI_FORMAT_R16_SNORM = 58,
    DXGI_FORMAT_R16_SINT = 59,
    DXGI_FORMAT_R8_TYPELESS = 60,
    DXGI_FORMAT_R8_UNORM = 61,
    DXGI_FORMAT_R8_UINT = 62,
    DXGI_FORMAT_R8_SNORM = 63,
    DXGI_FORMAT_R8_SINT = 64,
    DXGI_FORMAT_A8_UNORM = 65,
    DXGI_FORMAT_R1_UNORM = 66,
    DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
    DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
    DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
    DXGI_FORMAT_BC1_TYPELESS = 70,
    DXGI_FORMAT_BC1_UNORM = 71,
    DXGI_FORMAT_BC1_UNORM_SRGB = 72,
    DXGI_FORMAT_BC2_TYPELESS = 73,
    DXGI_FORMAT_BC2_UNORM = 74,
    DXGI_FORMAT_BC2_UNORM_SRGB = 75,
    DXGI_FORMAT_BC3_TYPELESS = 76,
    DXGI_FORMAT_BC3_UNORM = 77,
    DXGI_FORMAT_BC3_UNORM_SRGB = 78,
    DXGI_FORMAT_BC4_TYPELESS = 79,
    DXGI_FORMAT_BC4_UNORM = 80,
    DXGI_FORMAT_BC4_SNORM = 81,
    DXGI_FORMAT_BC5_TYPELESS = 82,
    DXGI_FORMAT_BC5_UNORM = 83,
    DXGI_FORMAT_BC5_SNORM = 84,
    DXGI_FORMAT_B5G6R5_UNORM = 85,
    DXGI_FORMAT_B5G5R5A1_UNORM = 86,
    DXGI_FORMAT_B8G8R8A8_UNORM = 87,
    DXGI_FORMAT_B8G8R8X8_UNORM = 88,
    DXGI_FORMAT_FORCE_UINT = 0xffffffffUL,
};

enum D3D10_RESOURCE_DIMENSION
{
    D3D10_RESOURCE_DIMENSION_UNKNOWN = 0,
    D3D10_RESOURCE_DIMENSION_BUFFER = 1,
    D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
    D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
    D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4,
};

//PixelFormat flags
const unsigned int DDPF_RGB = 0x40U;
const unsigned int DDPF_FOURCC = 0x4U;
const unsigned int DDPF_ALPHAPIXELS = 0x1U;

//Header flags
const unsigned int DDSD_CAPS = 0x1U;
const unsigned int DDSD_HEIGHT = 0x2U;
const unsigned int DDSD_WIDTH = 0x4U;
const unsigned int DDSD_PITCH = 0x8U;
const unsigned int DDSD_PIXELFORMAT = 0x1000U;
const unsigned int DDSD_MIPMAPCOUNT = 0x20000U;
const unsigned int DDSD_LINEARSIZE = 0x80000U;
const unsigned int DDSD_DEPTH = 0x800000U;

//Caps
const unsigned int DDSCAPS_COMPLEX = 0x8U;
const unsigned int DDSCAPS_TEXTURE = 0x1000U;
const unsigned int DDSCAPS_MIPMAP = 0x400000U;

const unsigned int DDSCAPS2_CUBEMAP = 0x200U;
const unsigned int DDSCAPS2_CUBEMAP_POSITIVEX = 0x400U;
const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800U;
const unsigned int DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000U;
const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000U;
const unsigned int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000U;
const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000U;
const unsigned int DDSCAPS2_VOLUME = 0x200000U;

struct DDSPIXELFORMAT
{
    unsigned int dwSize;
    unsigned int dwFlags;
    unsigned int dwFourCC;
    unsigned int dwRGBBitCount;
    unsigned int dwRBitMask;
    unsigned int dwGBitMask;
    unsigned int dwBBitMask;
    unsigned int dwABitMask;
} __attribute__((packed));

struct DDS_HEADER
{
    unsigned int dwSize;
    unsigned int dwFlags;
    unsigned int dwHeight;
    unsigned int dwWidth;
    unsigned int dwPitchOrLinearSize;
    unsigned int dwDepth;
    unsigned int dwMipMapcount;
    unsigned int dwReserved1[11];
    DDSPIXELFORMAT ddpfPixelFormat;
    unsigned int dwCaps;
    unsigned int dwCaps2;
    unsigned int dwCaps3;
    unsigned int dwCaps4;
    unsigned int dwReserved2;
};

struct DDS_HEADER_DXT10
{
    DXGI_FORMAT dxgiFormat;
    D3D10_RESOURCE_DIMENSION resourceDimension;
    unsigned int miscFlag;
    unsigned int arraySize;
    unsigned int reserved;
};

unsigned int getMipMapsSize( unsigned int width, unsigned int height, unsigned int depth, unsigned n)
{
    unsigned int res = 0;

    for( unsigned int i = 0; i < n; i++)
    {
        res += width*height*depth;

        width /= 2;
        height /= 2;
        depth /= 2;

        if( width < 1)
            width = 1;
        if( height < 1)
            height = 1;
        if( depth < 1)
            depth = 1;
    }

    return res;
}

void findNextFace( const DDS_HEADER & header, GLenum & face)
{
    switch( face)
    {
        case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEX))
            {
                face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
                break;
            }

        case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEY))
            {
                face = GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
                break;
            }

        case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEY))
            {
                face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
                break;
            }

        case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEZ))
            {
                face = GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
                break;
            }

        case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEZ))
            {
                face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
                break;
            }
        case GL_NONE:
        case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:

            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEX))
            {
                face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
                break;
            }

            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEX))
            {
                face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
                break;
            }

            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEY))
            {
                face = GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
                break;
            }

            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEY))
            {
                face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
                break;
            }

            if( CHECK_FLAGS( header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEZ))
            {
                face = GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
                break;
            }
    }
}

bool Image::loadDDS( std::string filename)
{
    //Read file header
    std::ifstream file(filename.c_str());

    if( !file)
    {
        wxLogError(_("Unable to open %s.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        return false;
    }

    unsigned int magic;
    file >> magic;

    if( magic != FOURCC_DDS)
    {
        wxLogError(_("In file %s, DDS magic number mismatch, it must be \"DDS \", is it really a DDS file ?.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    DDS_HEADER header;
    file.read( (char*)&header, sizeof(header));


    //Check header size and flags
    if( header.dwSize != sizeof( header))
    {
        wxLogError(_("In file %s, bad DDS header structure size, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    if( NCHECK_FLAGS(header.dwFlags, DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT))
    {
        wxLogError(_("In file %s, DDS header should have at least DDSD_CAPS, DDSD_HEIGHT, DDSD_WIDTH and DDSD_PIXELFORMAT flags, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    if( header.ddpfPixelFormat.dwSize != sizeof( header.ddpfPixelFormat))
    {
        wxLogError(_("In file %s, bad DDS pixelformat structure size, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    //Read DX10 header, if any
    bool hasDX10 = header.ddpfPixelFormat.dwFourCC == FOURCC_DX10;

    DDS_HEADER_DXT10 header10;
    if( hasDX10)
        file.read( (char*)&header10, sizeof(header10));

    //Check Caps and fill Image type member
    if( NCHECK_FLAGS(header.dwCaps, DDSCAPS_TEXTURE))
    {
        wxLogError(_("In file %s, DDS header should have at least DDSCAPS_TEXTURE capability, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    unsigned int cubeMapFaceCount = 1;

    if( CHECK_FLAGS(header.dwCaps, DDSCAPS_COMPLEX))
    {
        if( CHECK_FLAGS(header.dwCaps2,DDSCAPS2_CUBEMAP))
        {
            if( type != GL_NONE)
            {
                wxLogError(_("In file %s, unable to find image type (1D, 2D, 3D, …), this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
                file.close();
                return false;
            }

            type = GL_TEXTURE_CUBE_MAP;
            cubeMapFaceCount =  (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEX)
                                + (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEX)
                                + (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEY)
                                + (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEY)
                                + (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_POSITIVEZ)
                                + (unsigned int)CHECK_FLAGS(header.dwCaps2, DDSCAPS2_CUBEMAP_NEGATIVEZ);
        }

        if( CHECK_FLAGS(header.dwCaps2, DDSCAPS2_VOLUME))
        {
            if( type != GL_NONE)
            {
                wxLogError(_("In file %s, unable to find image type (1D, 2D, 3D, …), this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
                file.close();
                return false;
            }

            type = GL_TEXTURE_3D;

            if( NCHECK_FLAGS(header.dwFlags, DDSD_DEPTH))
            {
                wxLogError(_("In file %s, DDSD_DEPTH should be set if DDSCAPS2_VOLUME is used, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
                file.close();
                return false;
            }
        }
        else
            header.dwFlags &= ~DDSD_DEPTH;

        if( type == GL_NONE)
            type = GL_TEXTURE_2D;

        if( NCHECK_FLAGS(header.dwCaps, DDSCAPS_MIPMAP))
        {
            if( NCHECK_FLAGS(header.dwFlags, DDSD_MIPMAPCOUNT))
            {
                wxLogError(_("In file %s, DDSD_MIPMAPCOUNT should be set if DDSCAPS_MIPMAP is used, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
                file.close();
                return false;
            }
        }
        else
            header.dwFlags &= ~DDSD_MIPMAPCOUNT;
    }
    else
    {
        header.dwFlags &= ~DDSD_DEPTH;
        header.dwFlags &= ~DDSD_MIPMAPCOUNT;
    }

    //Fill Image information
    unsigned int width, height, depth;

    width = header.dwWidth;
    height = header.dwHeight;

    if( header.dwFlags ^ DDSD_DEPTH)
        depth = 1;
    else
        depth = header.dwDepth;

    unsigned int mips = 1;
    if( !(header.dwFlags ^ DDSD_MIPMAPCOUNT))
        mips = header.dwMipMapcount;

    //Fill dwRGBAlphaBitMask if not already used
    if( NCHECK_FLAGS(header.ddpfPixelFormat.dwFlags, DDPF_ALPHAPIXELS))
        header.ddpfPixelFormat.dwABitMask = 0;


    unsigned int blockSize, widthBlockSize, heightBlockSize, depthBlockSize;
    unsigned int format;
    unsigned int pixelType;
    unsigned int w, h, d;
    bool swap = false;

    if( CHECK_FLAGS(header.ddpfPixelFormat.dwFlags, DDPF_FOURCC)) //Compressed data
    {
        //Find blocksize and OpenGl appropriate format
        widthBlockSize = 4; heightBlockSize = 4; depthBlockSize = 1;

        if(header.ddpfPixelFormat.dwFourCC == FOURCC_DXT1)
        {
            blockSize = 8;
            format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
        }
        else if(header.ddpfPixelFormat.dwFourCC == FOURCC_DXT3)
        {
            blockSize = 16;
            format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
        }
        else if(header.ddpfPixelFormat.dwFourCC == FOURCC_DXT5)
        {
            blockSize = 16;
            format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
        }
        else
        {
            if((header.ddpfPixelFormat.dwFourCC == FOURCC_DXT2)
                || header.ddpfPixelFormat.dwFourCC == FOURCC_DXT4)
                wxLogError(_("The file %s use DXT2 or DXT4 compression format wich are unsupported by OpenGl, please replace those formats by respectively DXT3 or DXT5.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
            else
                wxLogError(_("The file %s use a unrecognized compression format, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
            file.close();
            return false;
        }

        if( type == GL_TEXTURE_3D)
        {
            wxLogError(_("The file %s use a compressed 3d texture, we couldn’t read such thing, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
            file.close();
            return false;
        }

        //Find image size and read buffer for image and its mimaps.
        w = (width + 3)/4; h = (height + 3)/4; d = 1;
        pixelType = GL_NONE;
    }
    else if( CHECK_FLAGS(header.ddpfPixelFormat.dwFlags, DDPF_RGB)) //Uncompressed data
    {
        w = width; h = height; d = depth;
        blockSize = header.ddpfPixelFormat.dwRGBBitCount/8;
        widthBlockSize = 1; heightBlockSize = 1; depthBlockSize = 1;

        if( (header.ddpfPixelFormat.dwRGBBitCount == 32)
            && (header.ddpfPixelFormat.dwRBitMask == 0xff0000)
            && (header.ddpfPixelFormat.dwGBitMask == 0xff00)
            && (header.ddpfPixelFormat.dwBBitMask == 0xff)
            && (header.ddpfPixelFormat.dwABitMask == 0xff000000))
        {
            format = GL_BGRA;
            pixelType = GL_UNSIGNED_BYTE;
        }
        else if( (header.ddpfPixelFormat.dwRGBBitCount == 24)
            && (header.ddpfPixelFormat.dwRBitMask == 0xff0000)
            && (header.ddpfPixelFormat.dwGBitMask == 0xff00)
            && (header.ddpfPixelFormat.dwBBitMask == 0xff)
            && (header.ddpfPixelFormat.dwABitMask == 0))
        {
            format = GL_BGR;
            pixelType = GL_UNSIGNED_BYTE;
        }
        else if( (header.ddpfPixelFormat.dwRGBBitCount == 16)
            && (header.ddpfPixelFormat.dwRBitMask == 0x00007c00)
            && (header.ddpfPixelFormat.dwGBitMask == 0x000003e0)
            && (header.ddpfPixelFormat.dwBBitMask == 0x0000001f)
            && (header.ddpfPixelFormat.dwABitMask == 0x00008000))
        {
            format = GL_BGRA;
            pixelType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
            swap = true;
        }
        else if( (header.ddpfPixelFormat.dwRGBBitCount == 16)
            && (header.ddpfPixelFormat.dwRBitMask == 0x0000f800)
            && (header.ddpfPixelFormat.dwGBitMask == 0x000007e0)
            && (header.ddpfPixelFormat.dwBBitMask == 0x0000001f)
            && (header.ddpfPixelFormat.dwABitMask == 0))
        {
            format = GL_RGB;
            pixelType = GL_UNSIGNED_SHORT_5_6_5_REV;
            swap = true;
        }
    }
    else //Unknow data
    {
        wxLogError(_("The file %s neither use DDPF_RGB uncompressed data nor DDPF_FOURCC compressed data, format is unrecognized, this file may be corrupted.") , wxString(filename.c_str() ,wxConvUTF8).c_str());
        file.close();
        return false;
    }

    unsigned int totalSize = getMipMapsSize(w, h, d, mips)* blockSize * cubeMapFaceCount;
    unsigned char* buffer = new unsigned char[totalSize];
    file.read( (char*)buffer, totalSize);

    //Create mipmaps
    images = new SubImage[mips];
    GLenum face = GL_NONE;

    for( unsigned int i=0; i < mips; i++)
    {
        for( unsigned int j=0; j < cubeMapFaceCount; j++)
        {
            if( type == GL_TEXTURE_CUBE_MAP) //Find next image face
            {
                findNextFace(header, face);
            }

            images[j*mips + i].buffer = buffer;
            images[j*mips + i].deleteBuffer = false;
            images[j*mips + i].mip = i;
            images[j*mips + i].format = format;
            images[j*mips + i].type = pixelType;
            images[j*mips + i].width = w*widthBlockSize;
            images[j*mips + i].height = h*heightBlockSize;
            images[j*mips + i].depth = d*depthBlockSize;
            images[j*mips + i].swap = swap;
            images[j*mips + i].face = face;
            images[j*mips + i].imageSize = w*h*d*blockSize;

            buffer += w*h*d*blockSize;
            w /= 2; h /= 2; d /= 2;
            if( w < 1)
                w = 1;
            if( h < 1)
                h = 1;
            if( d < 1)
                d = 1;
            //TODO : Swap Buffers row
        }
    }

    //TODO : texture arrays and floating point texture
    file.close();
    return true;
}
